package com.putable.nmc.dmv;

import com.putable.nmc.world.XRandom;


/**
 * 
 * @author Todd
 *
 * Implementation of the CustomerLine which can add, remove, or delete 
 * CLineAbles in constant time
 * 
 * Also, this implements and checks for the retiree talk and fear factors
 * whenever add or delete is called
 */
public class CustomerLine {
	
	int size; //The size of the line
	XRandom rand = new XRandom(Seed.seed);
	
	private CLineAble last, first;//The first and last customers in line
	/**
	 * Adds a customer to the queue
	 * @param c Customer to be added to the queue
	 * @param time TODO
	 */
	public void add(CLineAble c, double time){
		if(last == null){
			first = c;
			c.setCustInFront(null); // first in line
		}else{
			c.setCustInFront(last);//set to back of line
			last.setCustBehind(c);
		}
		c.setCustBehind(null);
		last = c;
		size ++;
		if(c.getPQueue() != null)
			checkCustomerInFront(c, time);
	}
	/**
	 * Gets and removes the first Customer in line
	 * @return The first Customer in line
	 */
	public CLineAble remove(){
		if(first == null){
			throw new NullPointerException("Line is Empty");
		}
		size --;
		CLineAble c = first;
		if(first == last) {
			//If removing last item. Removes all references to first and last
			first = last = null;
			return c;
		}
		first = c.getCustBehind();
		if(first != null)first.setCustInFront(null);
		return c;
	}
	/**
	 * Deletes customer c from the line
	 * @param c The customer we are deleting
	 * @param time The current time
	 */
	public void delete(CLineAble c, double time){
		if(c == null || (c.getCustBehind() == null && c.getCustInFront() == null && !(c == first && c == last)) ){
			throw new NullPointerException("That Customer is Not in Line");
		}
		//Sets the customer in front to be behind the customer c is behind and vice versa
		if(c.getCustInFront() != null){
			c.getCustInFront().setCustBehind(c.getCustBehind());
		}
		CLineAble custBehind = null;
		if(c.getCustBehind() != null){
			custBehind = c.getCustBehind();
			c.getCustBehind().setCustInFront(c.getCustInFront());
		}
		if(c == first && c == last){
			first = null;
			last = null;
		}
		size --;
		if(custBehind != null && c.getPQueue() != null) 
			checkCustomerInFront(custBehind,time);
	}
	/**
	 * Checks if the Line is empty
	 * @return whether or not the line is empty
	 */
	public boolean isEmpty(){
		boolean empty = false;
		if(first == null){
			empty = true;
		}
		return empty;
	}
	/**
	 * @return The size of the Line
	 */
	public int getSize(){
		if(isEmpty()) size = 0;
		return size;
	}
	/**
	 * @return The First CLineAble in line
	 */
	public CLineAble getFirst(){
		return first;
	}
	/**
	 * Checks the customer in front of c to see if the CLineAble will get scared
	 * or want to talk. Should be called each time add of delete is called. 
	 * @param c The CLineAble we are checking
	 * @param time The current time
	 */
	private void checkCustomerInFront(CLineAble c, double time){
		
		if(c.getCustInFront() != null){
			if(c.getCustInFront().getType() == CustType.RETIREE){
				CLineAble r = c.getCustInFront();
				if(c.getType() == CustType.BIKER){
					//if it is a biker, the customer may or may not get scared
					if (rand.nextProbability(1/(r.getWorld().getManagers()+1))){
						r.getPQueue().delete(r);
						double nextTask = r.getTimeOfNextTask() - r.getType().retireeFearFactor;
						if(nextTask < time){
							r.getWorld().exitInterview(r.getCit());
						}else{
							r.setTimeOfNextTask(nextTask);
							r.getPQueue().insert(r);
						}
					}	
				}else if (c.getType() == CustType.RETIREE){
					r.getPQueue().delete(r);
					r.setTimeOfNextTask(r.getTimeOfNextTask() + r.getType().retireeTalkFactor);
					r.getPQueue().insert(r);
				}
			}
		}
	}
}
